home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Skunkware 5
/
Skunkware 5.iso
/
src
/
X11
/
splines
/
splines.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-05-03
|
34KB
|
1,177 lines
/*
* @(#) splines.c 1.8 93/11/02 MRINC
*
* Written using CGI 5 October 1987 by Ron Record (sco!rr)
* Rewritten using X11 20 Apr 1993 by Ron Record (rr@sco.com)
*/
/*************************************************************************
* *
* Copyright (c) 1987-1993 Ronald Joe Record *
* *
* All rights reserved. No part of this program or publication may be *
* reproduced, transmitted, transcribed, stored in a retrieval system, *
* or translated into any language or computer language, in any form or *
* by any means, electronic, mechanical, magnetic, optical, chemical, *
* biological, or otherwise, without the prior written permission of: *
* *
* Ronald Joe Record (408) 458-3718 *
* 212 Owen St., Santa Cruz, California 95062 USA *
* *
*************************************************************************/
#include "splines.h"
#define BMAX 32
#define M_ESIZ 512
#define M_X 12
#define M_Y 8
#define M_DELTA 0.05
#define MAX_CINC 8
typedef struct {
int x,y;
int xdir, ydir;
int color;
} BALL;
BALL balls[BMAX];
int xradius=5, yradius=4, erase_balls=1, erase_curve=0, c_color, ch_wheel=1;
int lines=0, curve=1, nsteps=0, showballs=0, nballs=4, nsplines=1, e_color;
int naptime=0, stopping=1, now_c=0, delay_erase=1, esiz=64, s_order=3;
int nummaps=1, delay=0, bezier=0, spinlines=0, solospin=0;
int useroot=0, Fflag=0, oflag=0, ranwalk=0, ranflag=0, spin=0, xor=0;
int width=0, height=0, maxcolor, numfreecols;
int ***ctrl;
long limit=0, num_c=1;
double *theta;
int *radius;
char *outname;
/* routines declared in this file */
void event_loop(), usage(), init_contexts(), drawball(), redraw(), Clear();
void init_ctrl(), init_pts(), print_help(), drawspline(), ranparams();
void redisplay(), resize(), save(), move(), parseargs(), Getkey();
void freemem(), setupmem();
/* external routines used in this file */
extern int rand();
extern void Draw_spline(), Draw_bez();
void
usage()
{
printf("Usage: splines [-abefrsuxBEFIRW][-w width][-h height][-o file]\n");
printf("\t[-m index][-c colorwheel][-n count][-N nballs][-l limit]\n");
printf("\t[-p nsteps][-D delay][-S naptime][-X xradius][-Y yradius]\n");
printf("\t-a indicates display control points only\n");
printf("\t-B indicates Bezier rather than B-spline\n");
printf("\t-b indicates display cubic curves only\n");
printf("\t-c selects color wheel\n");
printf("\t-D specifies the spin delay\n");
printf("\t-E indicates erasure of previous control points\n");
printf("\t-e indicates erasure of previous curve\n");
printf("\t-f indicates display control points as circles\n");
printf("\t-I indicates infinite mode\n");
printf("\t-l sets the limit of number of curves to be calculated\n");
printf("\t-N sets the number of control points\n");
printf("\t-n sets the limit of number of sequences of curves\n");
printf("\t-p sets the number of steps used in spline calculation\n");
printf("\t-R indicates use of the root window\n");
printf("\t-r indicates random selection of parameters\n");
printf("\t-S sets the delay between curves\n");
printf("\t-s indicates spin color wheel when done computing\n");
printf("\t-R indicates use the root window\n");
printf("\t-m # indicates a minimum color index of # (0-255)\n");
printf("\t-o file will save the output as 'file' in PPM format\n");
printf("\t-W specifies a pseudo-random walk of the control points\n");
printf("\t-w # indicates a window width of #\n");
printf("\t-X sets the X radius of control point disks\n");
printf("\t-x indicates use of XOR rather than COPY mode\n");
printf("\t-Y sets the Y radius of control point disks\n");
printf("\t-h # indicates a window height of #\n");
printf("\t-u produces this message\n");
printf("During display :\n");
printf("\t'f' or 'F' will save the picture as a PPM file\n");
printf("\t'r' or 's' will spin the color wheel forwards or backwards\n");
printf("\t'W' will increment and 'w' decrement the color map selection\n");
printf("\t'?' or 'h' will display the usage message\n");
printf("\t'q' or 'Q' will quit\n");
}
void
freemem()
{
static int i, j;
for (i=0;i<M_ESIZ;i++) {
for (j=0;j<nballs;j++)
free(ctrl[i][j]);
free(ctrl[i]);
}
free(ctrl);
free(theta);
free(radius);
}
void
setupmem()
{
static int i, j;
if ((ctrl = (int ***)malloc((unsigned)((M_ESIZ+1)*sizeof(int **)))) == NULL) {
fprintf(stderr, "Error malloc'ing ctrl\n");
exit(-1);
}
if ((theta = (double *)malloc((unsigned)M_ESIZ*sizeof(double))) == NULL) {
fprintf(stderr, "Error malloc'ing theta\n");
exit(-1);
}
if ((radius = (int *)malloc((unsigned)M_ESIZ*sizeof(int))) == NULL) {
fprintf(stderr, "Error malloc'ing radius\n");
exit(-1);
}
for (i=0;i<M_ESIZ;i++) {
if ((ctrl[i]=(int **)malloc((unsigned)((nballs+1)*sizeof(int *))))==NULL){
fprintf(stderr, "Error malloc'ing ctrl[%d]\n",i);
exit(-1);
}
for (j=0;j<nballs;j++) {
if ((ctrl[i][j] = (int *)malloc((unsigned)(2*sizeof(int))))==NULL) {
fprintf(stderr, "Error malloc'ing ctrl[%d][%d]\n",i,j);
exit(-1);
}
}
}
}
void
drawspline(col, n)
int col, n;
{
static int i, j, k, m;
XSegment points[BMAX];
extern XSegment clipline();
extern double sin(), cos();
if (lines) {
for (i=0; i<(nballs/2); i++) {
j = 2*i;
points[i].x1 = ctrl[n][j][0];
points[i].y1 = ctrl[n][j][1];
points[i].x2 = ctrl[n][j+1][0];
points[i].y2 = ctrl[n][j+1][1];
}
XDrawSegments(dpy,pixmap,Data_GC[xor][col],points,nballs/2);
XDrawSegments(dpy,canvas,Data_GC[xor][col],points,nballs/2);
}
else if (spinlines) {
m = solospin ? 1 : nballs;
for (i=0; i<m; i++) {
j = radius[n] * sin(theta[n]);
k = radius[n] * cos(theta[n]);
points[i].x1 = j + ctrl[n][i][0];
points[i].y1 = k + ctrl[n][i][1];
points[i].x2 = ctrl[n][i][0] - j;
points[i].y2 = ctrl[n][i][1] - k;
points[i] = clipline(points[i],0,width,0,height);
}
XDrawSegments(dpy,pixmap,Data_GC[xor][col],points,m);
XDrawSegments(dpy,canvas,Data_GC[xor][col],points,m);
theta[(n+1)%esiz] = theta[n] + M_DELTA;
if (theta[(n+1)%esiz] > M_2PI)
theta[(n+1)%esiz] = theta[(n+1)%esiz] - M_2PI;
if (n < (esiz/2))
radius[(n+1)%esiz] = Max(radius[n] + 1, 1);
else
radius[(n+1)%esiz] = Max(radius[n] - 1, 1);
}
else {
j = (nballs / nsplines);
for (i=0; i<nsplines; i++) {
if (bezier)
Draw_bez(dpy,canvas,pixmap,Data_GC[xor][col],
&ctrl[n][i*j],j-1,nsteps);
else
Draw_spline(dpy,canvas,pixmap,Data_GC[xor][col],
&ctrl[n][i*j],j-1,nsteps,s_order);
}
}
}
void
ranparams()
{
delay_erase = rand() % 2;
curve = rand() % 2;
showballs = rand() % 2;
if ((!curve) && (!showballs))
if (rand() % 2)
curve = 1;
else
showballs = 1;
if (delay_erase && curve) {
showballs = xor = 0;
}
else {
xor = rand() % 2;
}
erase_curve = rand() % 2;
erase_balls = rand() % 2;
spin = rand() % 2;
Fflag = rand() % 2;
bezier = rand() % 2;
lines = (!(rand() % 6));
spinlines = (!(rand() % 6));
nballs = rand() % BMAX;
if (nballs < 3)
nballs = 3;
nsplines = (rand() % (nballs/3)) + 1;
if (nsplines < 1)
nsplines = 1;
if (nsplines > (nballs/3))
nsplines = nballs/3;
/* work-around bug whereby if nballs>13 per Bezier spline, */
/* the spline is always anchored at the origin */
if (bezier && ((nballs/nsplines) > 13))
bezier = 0;
nsteps = ((nballs/nsplines) * 2) + (rand() % 50);
if (rand() % 4)
naptime = 0;
else
naptime = rand() % (450 / nballs);
numwheels = rand() % (MAXWHEELS + 1);
}
void
init_contexts()
{
static int i, j;
XGCValues values;
/*
* create default, writable, graphics contexts for the canvas.
* the first index indicates whether the context draws in XOR mode.
* the second index indicates what the foreground color is.
*/
values.background = BlackPixel(dpy, screen);
for (j=0; j<2; j++) {
if (j)
values.function = GXxor;
else
values.function = GXcopy;
Data_GC[j][0] = XCreateGC(dpy, DefaultRootWindow(dpy),
(unsigned long) NULL, (XGCValues *) NULL);
/* set the background to black */
XSetBackground(dpy,Data_GC[j][0],BlackPixel(dpy, screen));
/* set the foreground of the 0th context to black */
XSetForeground(dpy, Data_GC[j][0], BlackPixel(dpy, screen));
Data_GC[j][1] = XCreateGC(dpy, DefaultRootWindow(dpy),
(unsigned long) NULL, (XGCValues *) NULL);
/* set the background to black */
XSetBackground(dpy,Data_GC[j][1],BlackPixel(dpy, screen));
/* set the foreground of the 1st context to white */
XSetForeground(dpy, Data_GC[j][1], WhitePixel(dpy, screen));
for (i=2; i<maxcolor; i++) {
values.foreground = i;
Data_GC[j][i] = XCreateGC(dpy, DefaultRootWindow(dpy),
GCForeground | GCBackground | GCFunction, &values);
}
}
}
void
Clear()
{
XFillRectangle(dpy, pixmap, Data_GC[0][0], 0, 0, width, height);
XCopyArea(dpy, pixmap, canvas, Data_GC[0][0], 0, 0, width, height, 0, 0);
}
void
init_ball(k)
int k;
{
balls[k].x = (int)((rand()%(width-2))+1);
balls[k].y = (int)((rand()%(height-2))+1);
balls[k].xdir = (rand()&0xff) > 128 ? rand()%M_X+1 :-(rand()%M_X+1);
balls[k].ydir = (rand()&0xff) > 128 ? rand()%M_Y+1 :-(rand()%M_Y+1);
balls[k].color = (rand() % numfreecols) + STARTCOLOR;
}
void
init_ctrl()
{
int i;
for (i=0;i<nballs;i++) {
ctrl[now_c][i][0] = balls[i].x;
ctrl[now_c][i][1] = balls[i].y;
}
}
void
init_pts()
{
int i;
for (i=0;i<nballs;i++) {
init_ball(i);
if (showballs)
drawball(i, balls[i].color);
}
}
initialize()
{
Clear();
num_c = 1;
now_c = 0;
theta[0] = 0.0;
radius[0] = 1;
init_pts();
init_ctrl();
c_color = STARTCOLOR;
if (xor)
e_color = c_color;
else
e_color = 0;
if (curve) /* Draw the initial spline curve */
drawspline(c_color, now_c);
}
#define x_str 10
void
print_help()
{
static char str[80];
static int y_str, spacing;
static int ascent, descent, dir;
static XCharStruct overall;
static GC gc;
gc = Data_GC[0][1];
XClearWindow(dpy, help);
y_str = 20;
sprintf(str,"During run-time, interactive control can be exerted via : ");
XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
XQueryTextExtents(dpy,(XID)XGContextFromGC(gc),"Hey!",
4,&dir,&ascent,&descent,&overall);
spacing = ascent + descent + 5;
y_str += spacing;
sprintf(str," < decreases delay between curves, > increases it");
XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
y_str += spacing;
sprintf(str," - lowers the value of mincolindex, + raises it");
XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
y_str += spacing;
sprintf(str," b or B toggles between Bezier and B-spline");
XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
y_str += spacing;
sprintf(str," c or C clears the window or creates a new control pt");
XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
y_str += spacing;
sprintf(str," d or D decreases or increases the spin delay");
XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
y_str += spacing;
sprintf(str," e or E toggles erasing of curves or control pts");
XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
y_str += spacing;
sprintf(str," f or F saves splines to a PPM file");
XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
y_str += spacing;
sprintf(str," g or G toggles display of ctrl pts as disks");
XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
y_str += spacing;
sprintf(str," h or H or ? displays this message");
XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
y_str += spacing;
sprintf(str," i or I toggles infinite mode");
XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
y_str += spacing;
sprintf(str," k or K toggles display of control pts or curves");
XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
y_str += spacing;
sprintf(str," L deletes a control point");
XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
y_str += spacing;
sprintf(str," n goes on to the next splines");
XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
y_str += spacing;
sprintf(str," N creates a new replacement splines");
XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
y_str += spacing;
sprintf(str," p or P decreases or increases the number of steps");
XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
y_str += spacing;
sprintf(str," R toggles a random walk of the control points");
XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
y_str += spacing;
sprintf(str," S stops the spinning of the color wheel");
XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
y_str += spacing;
sprintf(str," r or s spins the colorwheel");
XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
y_str += spacing;
sprintf(str," w decrements, W increments the color wheel index");
XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
y_str += spacing;
sprintf(str," X creates an additional control point");
XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
y_str += spacing;
sprintf(str," x toggles between XOR and COPY mode");
XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
y_str += spacing;
sprintf(str," q or Q exits");
XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
y_str += spacing;
sprintf(str,"Press 'h', 'H', or '?' to unmap the help window");
XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
}
void
redisplay (event)
XExposeEvent *event;
{
if ((event->window == help) && (!useroot))
print_help();
else {
/*
* Extract the exposed area from the event and copy
* from the saved pixmap to the window.
*/
XCopyArea(dpy, pixmap, canvas, Data_GC[0][0], event->x, event->y,
event->width, event->height, event->x, event->y);
}
}
void
resize()
{
Window r;
int j;
int x, y;
unsigned int bw, d, new_w, new_h;
XGetGeometry(dpy,canvas,&r,&x,&y,&new_w,&new_h,&bw,&d);
if (((int)new_w == width) && ((int)new_h == height))
return;
width = (int)new_w; height = (int)new_h;
if (pixmap)
XFreePixmap(dpy, pixmap);
pixmap = XCreatePixmap(dpy, DefaultRootWindow(dpy),
width, height, DefaultDepth(dpy, screen));
initialize();
}
void
Cleanup() {
XCloseDisplay(dpy);
}
/* Store splines growth in PPM format */
void
save()
{
FILE *outfile;
unsigned char c;
XImage *ximage;
static int i,j;
struct Colormap {
unsigned char red;
unsigned char green;
unsigned char blue;
};
struct Colormap *colormap=NULL;
if ((colormap=
(struct Colormap *)malloc((unsigned)sizeof(struct Colormap)*maxcolor))
== NULL) {
fprintf(stderr,"Error malloc'ing colormap array\n");
Cleanup();
exit(-1);
}
outfile = fopen(outname,"w");
if(!outfile) {
perror(outname);
Cleanup();
exit(-1);
}
ximage=XGetImage(dpy, pixmap, 0, 0, width, height, AllPlanes, ZPixmap);
for (i=0;i<maxcolor;i++) {
colormap[i].red=(unsigned char)(Colors[i].red >> 8);
colormap[i].green=(unsigned char)(Colors[i].green >> 8);
colormap[i].blue =(unsigned char)(Colors[i].blue >> 8);
}
fprintf(outfile,"P%d %d %d\n",6,width,height);
fprintf(outfile,"%d\n",maxcolor-1);
for (j=0;j<height;j++)
for (i=0;i<width;i++) {
c = (unsigned char)XGetPixel(ximage,i,j);
fwrite((char *)&colormap[c],sizeof colormap[0],1,outfile);
}
fclose(outfile);
free(colormap);
}
void
redraw()
{
static int i;
Clear();
if (curve) /* Redraw the erased spline curve */
drawspline(c_color, now_c);
if (showballs) /* Redraw the erased balls */
for (i=0; i<nballs; i++)
drawball(i, balls[i].color);
}
void
Getkey(event)
XKeyEvent *event;
{
char key;
static int spinning=0, spindir=0, i;
static XWindowAttributes attr;
extern void init_color(), write_cmap();
if (XLookupString(event, (char *)&key, sizeof(key), (KeySym *)0,
(XComposeStatus *) 0) > 0)
switch (key) {
case '\015': /*write out current colormap to $HOME/.<prog>map*/
write_cmap(dpy,cmap,Colors,maxcolor,"splines","Splines");
break;
case '<': naptime -= 20;
if (naptime < 0)
naptime = 0;
break;
case '>': naptime += 20;
break;
case '-': /* decrease nsteps */
nsteps -= 10;
if (nsteps < 1)
nsteps = 1;
redraw();
break;
case '+': /* Increase nsteps */
nsteps += 10;
redraw();
break;
case ']': mincolindex += INDEXINC;
if (mincolindex > maxcolor)
mincolindex = 1;
init_color(dpy,canvas,cmap,Colors,STARTCOLOR,
mincolindex,maxcolor,numwheels,"splines","Splines",0);
break;
case '[': mincolindex -= INDEXINC;
if (mincolindex < 1)
mincolindex = maxcolor - 1;
init_color(dpy,canvas,cmap,Colors,STARTCOLOR,
mincolindex,maxcolor,numwheels,"splines","Splines",0);
break;
case 'a':
case 'A': ch_wheel = (!ch_wheel);
break;
case 'b':
case 'B': bezier = (!bezier);
/* work-around bug whereby if nballs>13 per Bezier spline, */
/* the spline is always anchored at the origin */
if (bezier && ((nballs/nsplines) > 13))
nballs = nsplines * 13;
redraw();
break;
case 'c': /* clear the window */
redraw();
break;
case 'C': /* create a new ship, leaving the old */
if (nballs >= BMAX - 1)
break;
freemem();
nballs++;
/* work-around bug whereby if nballs>13 per Bezier spline, */
/* the spline is always anchored at the origin */
if (bezier && ((nballs/nsplines) > 13))
nballs = nsplines * 13;
setupmem();
if (spinlines)
initialize();
else {
init_ball(nballs-1);/* initialize new ship */
init_ctrl();
redraw();
}
break;
case 'd': delay -= 25; if (delay < 0) delay = 0; break;
case 'D': delay += 25; break;
case 'e': erase_curve = (!erase_curve);
if (erase_curve)
redraw();
break;
case 'E': erase_balls = (!erase_balls);
if (erase_balls)
redraw();
break;
case 'f': /* save in PPM format file */
case 'F': save(); break;
case 'g': Fflag = (!Fflag);
redraw();
break;
case 'G': /* toggle drawing solo spun lines */
solospin = (!solospin);
redraw();
break;
case 'i':
case 'I': stopping = (!stopping);
break;
case 'k': /* toggle display of balls */
showballs = (!showballs);
redraw();
break;
case 'K': /* toggle display of curves */
curve = (!curve);
redraw();
break;
case 'L': /* toggle drawing lines */
lines = (!lines);
redraw();
break;
case '\014': /* (ctrl-L) toggle drawing spinning lines */
spinlines = (!spinlines);
initialize();
break;
case 'l': /* delete a ball */
if (nballs <= 3)
break;
freemem();
nballs--;
setupmem();
redraw();
break;
case 'm': esiz /= 2; /* halve the length of the trail */
if (esiz < 1)
esiz = 1;
initialize();
break;
case 'M': esiz *= 2; /* double the length of the trail */
if (esiz > M_ESIZ)
esiz = M_ESIZ;
initialize();
break;
case 'N': /* go on to the next splines */
nummaps++; /* but don't increment the splines counter */
case 'n': /* go on to the next splines */
if (ranflag) {
freemem();
ranparams();
setupmem();
}
initialize();
break;
case 'o': /* decrease order of spline */
if (--s_order < 1)
s_order = 1;
redraw();
break;
case 'O': /* Increase order of spline */
if (++s_order > 4)
s_order = 4;
redraw();
break;
case 'p': /* decrease nsplines */
if (--nsplines < 1)
nsplines = 1;
redraw();
break;
case 'P': /* Increase nsplines */
if (++nsplines > nballs/3)
nsplines = nballs/3;
redraw();
break;
case 'R': ranwalk = (!ranwalk);
break;
case 'r': spinning=1; spindir=1;
Spin(dpy, cmap, Colors, STARTCOLOR, maxcolor, delay, 1);
break;
case 'S': spinning=0;
break;
case 's': spinning=1; spindir=0;
Spin(dpy, cmap, Colors, STARTCOLOR, maxcolor, delay, 0);
break;
case 'T': delay_erase = (!delay_erase);
if (delay_erase) {
showballs = 0; xor = 0;
e_color = 0;
}
now_c=0;
redraw();
break;
case '\027': /* (ctrl-W) read palette from $HOME/.splinesmap */
numwheels = 0;
init_color(dpy,canvas,cmap,Colors,STARTCOLOR,
mincolindex,maxcolor,numwheels,"splines","Splines",0);
break;
case 'W':
if (numwheels < MAXWHEELS)
numwheels++;
else
numwheels = 0;
init_color(dpy,canvas,cmap,Colors,STARTCOLOR,
mincolindex,maxcolor,numwheels,"splines","Splines",0);
break;
case 'w':
if (numwheels > 0)
numwheels--;
else
numwheels = MAXWHEELS;
init_color(dpy,canvas,cmap,Colors,STARTCOLOR,
mincolindex,maxcolor,numwheels,"splines","Splines",0);
break;
case '?':
case 'h':
if (!useroot) {
XGetWindowAttributes(dpy, help, &attr);
if (attr.map_state != IsUnmapped)
XUnmapWindow(dpy, help);
else {
XMapRaised(dpy, help);
print_help();
}
}
break;
case 'x': /* toggle drawing in XOR mode */
xor = (!xor);
if (xor)
e_color = c_color;
else
e_color = 0;
redraw();
break;
case 'X': /* create new splines, erasing the old */
nummaps++;
initialize();
break;
case 'Q':
case 'q': Cleanup(); exit(0); break;
}
if (spinning)
Spin(dpy, cmap, Colors, STARTCOLOR, maxcolor, delay, spindir);
}
void
parseargs(argc, argv)
int argc;
char *argv[];
{
int c;
extern int optind, getopt();
extern char *optarg;
outname = "splines.ppm";
while((c=getopt(argc,argv,
"abefrsuxBCEFGILRTWc:h:k:l:m:n:o:p:w:D:M:N:O:P:S:"))!=EOF)
{ switch(c)
{
case 'a': curve=0; showballs=1; break; /* balls only */
case 'b': curve=1; showballs=1; break; /* curve and balls */
case 'c':
numwheels = atoi(optarg);
if (numwheels > MAXWHEELS)
numwheels = MAXWHEELS;
if (numwheels < 0)
numwheels = 0;
break;
case 'e':
erase_curve++;
break;
case 'f':
Fflag=1;
break;
case 'u':
usage();
exit(0);
case 'h':
height = atoi(optarg);
break;
case 'l':
limit = atol(optarg);
break;
case 'm':
mincolindex = atoi(optarg);
break;
case 'n':
nummaps = atoi(optarg);
break;
case 'o':
++oflag;
outname = optarg;
break;
case 'p':
nsteps = atoi(optarg);
break;
case 'r':
++ranflag;
break;
case 's':
++spin;
break;
case 'w':
width = atoi(optarg);
break;
case 'x': /* use xor as drawing mode */
xor = 1;
break;
case 'B':
bezier++;
break;
case 'C': /* don't change color wheels automatically */
ch_wheel = 0;
break;
case 'D':
delay = atoi(optarg);
break;
case 'E':
erase_balls++;
break;
case 'F':
spinlines++;
break;
case 'G':
solospin++;
break;
case 'I':
stopping = 0;
break;
case 'L':
lines = 1;
break;
case 'M':
esiz = atoi(optarg);
if (esiz > M_ESIZ)
esiz = M_ESIZ;
if (esiz < 1)
esiz = 1;
break;
case 'N':
nballs = atoi(optarg);
if (nballs > BMAX)
nballs = BMAX;
if (nballs < 3)
nballs = 3;
break;
case 'O':
s_order = atoi(optarg);
if (s_order < 1)
s_order = 1;
if (s_order > 4)
s_order = 4;
break;
case 'P':
nsplines = atoi(optarg);
if (nsplines > BMAX)
nsplines = BMAX;
if (nsplines < 1)
nsplines = 1;
break;
case 'R':
useroot++;
ch_wheel = 0;
break;
case 'S':
naptime = atoi(optarg);
break;
case 'T':
delay_erase=0;
break;
case 'W': ranwalk++; break;
case 'X': xradius = atoi(optarg); break;
case 'Y': yradius = atoi(optarg); break;
case '?':
usage();
exit(1);
break;
}
}
if (ranflag)
ranparams();
if (nsplines > nballs/3)
nsplines = nballs/3;
/* work-around bug whereby if nballs>13 per Bezier spline, */
/* the spline is always anchored at the origin */
if (bezier && ((nballs/nsplines) > 13))
nballs = nsplines * 13;
}
void
event_loop()
{
int n;
XEvent event;
n = XEventsQueued(dpy, QueuedAfterFlush);
while (n-- > 0) {
XNextEvent(dpy, &event);
switch(event.type) {
case KeyPress:
Getkey(&event);
break;
case Expose:
if (useroot)
redraw();
else
redisplay(&event);
break;
case ConfigureNotify:
resize();
break;
}
}
}
void
drawball(i, col)
int i, col;
{
if (Fflag) {
XFillArc(dpy,pixmap,Data_GC[1][col],
balls[i].x-xradius,balls[i].y-yradius,
2*xradius,2*yradius,0,23040);
XFillArc(dpy,canvas,Data_GC[1][col],
balls[i].x-xradius,balls[i].y-yradius,
2*xradius,2*yradius,0,23040);
}
else {
XDrawArc(dpy,pixmap,Data_GC[1][col],
balls[i].x-xradius,balls[i].y-yradius,
2*xradius,2*yradius,0,23040);
XDrawArc(dpy,canvas,Data_GC[1][col],
balls[i].x-xradius,balls[i].y-yradius,
2*xradius,2*yradius,0,23040);
}
}
void
erase_old()
{
static int i;
if (spinlines)
Clear();
else
for (i=0; i<esiz; i++)
drawspline(0, i);
now_c = 0;
}
void
move()
{
static int i;
++num_c;
if (curve && erase_curve) /* Erase the drawn spline curve */
drawspline(e_color, now_c);
if (curve && delay_erase) {
if (num_c >= esiz) /* erase esiz ago curve */
drawspline(0, num_c % esiz);
if (++now_c >= esiz)
now_c = 0;
}
for( i=0; i<nballs; i++ )
{
if (showballs && erase_balls)
drawball(i, (erase_curve || delay_erase) ? 0 : balls[i].color);
if (ranwalk && ((rand()&0xff) > 192)) {
balls[i].xdir = (rand()&0xff) > 128 ? rand()%M_X+1 :-(rand()%M_X+1);
balls[i].ydir = (rand()&0xff) > 128 ? rand()%M_Y+1 :-(rand()%M_Y+1);
}
balls[i].x +=balls[i].xdir;
balls[i].y +=balls[i].ydir;
if( (balls[i].x <0) || (balls[i].x>width-1))
{
/* bounced off screen */
balls[i].xdir = -balls[i].xdir;
balls[i].x +=balls[i].xdir;
balls[i].x +=balls[i].xdir;
}
if( (balls[i].y <0) || (balls[i].y >height-1))
{
/* bounced off screen */
balls[i].ydir = -balls[i].ydir;
balls[i].y +=balls[i].ydir;
balls[i].y +=balls[i].ydir;
}
if( showballs )
drawball(i, balls[i].color);
if (curve) {
ctrl[now_c][i][0] = balls[i].x;
ctrl[now_c][i][1] = balls[i].y;
}
}
Timer(naptime);
if (curve) { /* Draw the new spline curve */
if (++c_color >= maxcolor) { /* increment the color index */
if (ch_wheel) {/*cannot be using the root window if ch_wheel set*/
if (ch_wheel++ == MAX_CINC) {
ch_wheel = 1;
if (curve && delay_erase)
erase_old();
if (numwheels > 0)
numwheels--;
else
numwheels = MAXWHEELS;
init_color(dpy,canvas,cmap,Colors,STARTCOLOR,
mincolindex,maxcolor,numwheels,"splines","Splines",0);
}
}
c_color = STARTCOLOR;
}
if (xor)
e_color = c_color;
drawspline(c_color, now_c);
}
}
main(argc,argv)
int argc;
char *argv[];
{
static int i, j;
static int count;
XSizeHints hint;
Atom __SWM_VROOT = None;
Window rootReturn, parentReturn, *children;
unsigned int numChildren;
extern void srand(), init_color();
srand((unsigned)time(0));
parseargs(argc,argv);
dpy = XOpenDisplay("");
screen = DefaultScreen(dpy);
if (useroot) {
width = XDisplayWidth(dpy, screen);
height = XDisplayHeight(dpy, screen);
}
if (width == 0)
width = XDisplayWidth(dpy, screen);
if (height == 0)
height = XDisplayHeight(dpy, screen);
if (nsteps == 0)
nsteps = 5 * (nballs/nsplines);
maxcolor = (int)XDisplayCells(dpy, screen);
if (maxcolor <= 16) {
STARTCOLOR = 2; delay = 100;
INDEXINC = 1; mincolindex = 5;
}
maxcolor = Min(maxcolor, MAXCOLOR);
numfreecols = maxcolor - STARTCOLOR;
if (limit == 0)
limit = width * height;
/*
* Create the pixmap to hold the splines growth
*/
pixmap = XCreatePixmap(dpy, DefaultRootWindow(dpy), width, height,
DefaultDepth(dpy, screen));
/*
* Create the window to display the fractal topographic map
*/
hint.x = 0;
hint.y = 0;
hint.width = width;
hint.height = height;
hint.flags = PPosition | PSize;
if (useroot) {
canvas = DefaultRootWindow(dpy);
/* search for virtual root (from ssetroot by Tom LaStrange) */
__SWM_VROOT = XInternAtom(dpy, "__SWM_VROOT", False);
XQueryTree(dpy,canvas,&rootReturn,&parentReturn,&children,&numChildren);
for (j = 0; j < numChildren; j++) {
Atom actual_type;
int actual_format;
long nitems, bytesafter;
Window *newRoot = NULL;
if (XGetWindowProperty (dpy, children[j], __SWM_VROOT,0,1, False,
XA_WINDOW, &actual_type, &actual_format, &nitems, &bytesafter,
(unsigned char **) &newRoot) == Success && newRoot) {
canvas = *newRoot;
break;
}
}
}
else {
canvas = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy),
0, 0, width, height, 5, 0, 1);
XSetStandardProperties(dpy, canvas, "Splines by Ron Record",
"Splines", None, argv, argc, &hint);
XMapRaised(dpy, canvas);
}
XChangeProperty(dpy, canvas, XA_WM_CLASS, XA_STRING, 8, PropModeReplace,
"splines", strlen("splines"));
/*
* Create the window used to display the help info (if not running on root)
*/
if (!useroot) {
hint.x = XDisplayWidth(dpy, screen) / 4;
hint.y = XDisplayHeight(dpy, screen) / 5;
hint.width = hint.x * 2;
hint.height = hint.y * 3;
help = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy),
hint.x, hint.y, hint.width, hint.height, 5, 0, 1);
XSetWindowBackground(dpy, help, BlackPixel(dpy, screen));
/* Title */
XSetStandardProperties(dpy,help,"Help","Help",None,argv,argc,&hint);
/* Try to write into a new color map */
cmap = XCreateColormap(dpy,canvas,DefaultVisual(dpy,screen),AllocAll);
init_color(dpy, canvas, cmap, Colors, STARTCOLOR, mincolindex, maxcolor,
numwheels,"splines", "Splines", 0);
/* install new color map */
XSetWindowColormap(dpy, canvas, cmap);
XSetWindowColormap(dpy, help, cmap);
}
init_contexts();
if (useroot)
XSelectInput(dpy,canvas,ExposureMask);
else {
XSelectInput(dpy,canvas,KeyPressMask|ExposureMask|StructureNotifyMask);
XSelectInput(dpy,help,KeyPressMask|ExposureMask);
}
setupmem();
for (i=0; i!=nummaps; i++) {
initialize();
for (;;) {
move();
event_loop();
if ((num_c > limit) && stopping)
break;
}
if (oflag)
save();
if (spin && (!useroot) && curve && (!erase_curve))
DemoSpin(dpy, cmap, Colors, STARTCOLOR, maxcolor, delay, 1);
freemem();
if (ranflag)
ranparams();
setupmem();
if (xor)
e_color = c_color;
else
e_color = 0;
if (!useroot)
init_color(dpy,canvas,cmap,Colors,STARTCOLOR,
mincolindex,maxcolor,numwheels,"splines","Splines",0);
}
XSetWindowBackgroundPixmap(dpy, canvas, pixmap);
for (i=0; i<maxcolor; i++) {
XFreeGC(dpy, Data_GC[0][i]);
XFreeGC(dpy, Data_GC[1][i]);
}
XFreePixmap(dpy, pixmap);
XClearWindow(dpy, canvas);
XFlush(dpy);
Cleanup();
exit(0);
}